package com.example.starter.redisson.aspectj;

import com.example.starter.redisson.anntation.RedissonLock;
import com.example.starter.redisson.handler.KeyGeneratorStrategyFactory;
import com.example.starter.redisson.handler.LockModeElectionStrategyFactory;
import com.example.starter.util.ExceptionUtil;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;

/**
 * @author 王令
 * @since 2022/11/14 12:23
 */
@Aspect
@RequiredArgsConstructor
public class RedissonLockAspect {

    @Around("@annotation(lock)")
    public Object around(ProceedingJoinPoint point, RedissonLock lock) {
        String key = KeyGeneratorStrategyFactory.election(lock).generate(point, lock);
        RLock rLock = LockModeElectionStrategyFactory.election(lock.mode(), key);
        Object proceed = null;
        try {
            if (rLock.tryLock(lock.waitTime(), lock.leaseTime(), lock.timeUnit())) {
                proceed = point.proceed();
            }
        } catch (Throwable e) {
            throw ExceptionUtil.wrap(e.getLocalizedMessage());
        } finally {
            if (rLock.isLocked()) {
                rLock.unlock();
            }
        }
        return proceed;
    }

}
